/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.saber.certificacao.ejbs.stateless;

import br.com.saber.certificacao.ejbs.stateless.interfaces.VersaoBeanLocal;
import br.com.saber.certificacao.enums.Linguagem;
import br.com.saber.certificacao.modelos.Certificacao;
import br.com.saber.certificacao.modelos.Usuario;
import br.com.saber.certificacao.modelos.Versao;
import br.com.saber.certificacao.modelos.relacionamentos.ProfessorVersao;
import br.com.saber.certificacao.modelos.validadores.VersaoValidador;
import br.com.saber.certificacao.modelos.validadores.interfaces.ValidadorInterface;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 *
 * @author gbvbahia
 */
@Stateless
public class VersaoBean implements VersaoBeanLocal {

    @PersistenceContext(name = "jdbc/saber")
    private EntityManager manager;

    @Override
    public void salvarVersao(Versao versao, List<Usuario> professores) {
        ValidadorInterface<Versao, VersaoBeanLocal> vv = new VersaoValidador();
        vv.validar(versao, this, null);
        if (versao.getId() == null) {
            manager.persist(versao);
        } else {
            manager.merge(versao);
        }
        manager.flush();
        manager.merge(addProfessor(versao, professores));
        manager.flush();
    }

    private Versao addProfessor(Versao versao, List<Usuario> professores) {
        if (professores != null && !professores.isEmpty()) {
            for (Usuario us : professores) {
                ProfessorVersao pv = new ProfessorVersao(us, versao);
                versao.getProfessoresDestaVersao().add(pv);
            }
        }
        return versao;
    }

    @Override
    public Versao buscarVersaoPorNome(String nome) {
        Query q = manager.createNamedQuery("VersaoBean.buscarVersaoPorNome");
        q.setParameter("nome", nome);
        try {
            return (Versao) q.getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }

    @Override
    public Versao buscarVersaoPorId(long parameter) {
        return manager.find(Versao.class, parameter);
    }

    @Override
    public Set<Versao> buscarTodasVersoes() {
        Query q = manager.createNamedQuery("VersaoBean.buscarTodasVersoes");
        return new TreeSet<Versao>(q.getResultList());
    }

    @Override
    public Set<Versao> buscarVersoesPorCertificacao(Certificacao certificacao) {
        Query q = manager.createNamedQuery("VersaoBean.buscarVersoesPorCertificacao");
        q.setParameter("certificacao", certificacao);
        return new TreeSet<Versao>(q.getResultList());
    }

     /**
     * Retorna todas as versões da certificação passada limitada as visão se a versão 
     * é superior ou não.
     * @param certificacao
     * @param isMother
     * @return 
     */
    @Override
    public Set<Versao> buscarVersoesPorCertificacao(Certificacao certificacao, boolean isMother){
        Set<Versao> toReturn = new TreeSet<Versao>();
        for(Versao ver : buscarVersoesPorCertificacao(certificacao)){
            if(ver.isMother() == isMother){
                toReturn.add(ver);
            }
        }
        return toReturn;
    }
    
    /**
     * Embora em sua nomenclatura seja professor, será retornado
     * todas as versões atrelada ao usuário passado, Coordenador,
     * professor, usuário.
     * Havendo uma ligação ProfessorVersao a versão será retornada.
     * @param professor
     * @return Havendo uma ligação ProfessorVersao a versão será retornada.
     */
    @Override
    public Set<Versao> buscarVersoesPorProfessor(Usuario professor) {
        Query q = manager.createNamedQuery("VersaoBean.buscarVersoesPorProfessor");
        q.setParameter("professor", professor);
        TreeSet<Versao> toReturn = new TreeSet<Versao>();
        List<ProfessorVersao> pvs = q.getResultList();
        for (ProfessorVersao pv : pvs) {
            toReturn.add(pv.getVersao());
        }
        return toReturn;
    }

    /**
     * Retorna todas as versões que o usuario(professor) tem acesso
     * limitado a certificação passada, versões que não sejam da Certificação
     * passada são ignoradas.
     * @param professor
     * @param certificacao
     * @return @return Havendo uma ligação ProfessorVersao a versão e a versão
     * seja da certificação informada, esta versão será retornada dentro do Set.
     */
    @Override
    public Set<Versao> buscarVersaoPorProfessorCertificacao(Usuario professor, Certificacao certificacao) {
        Query q = manager.createNamedQuery("VersaoBean.buscarVersaoProProfessorCertificacao");
        q.setParameter("professor", professor);
        q.setParameter("certificacao", certificacao);
        TreeSet<Versao> toReturn = new TreeSet<Versao>();
        List<ProfessorVersao> pvs = q.getResultList();
        for (ProfessorVersao pv : pvs) {
            toReturn.add(pv.getVersao());
        }
        return toReturn;
    }

    @Override
    public Set<Versao> buscarVersaoPorProfessorCertificacao(Usuario professor, Certificacao certificacao, boolean isMother) {
        Query q = manager.createNamedQuery("VersaoBean.buscarVersaoProProfessorCertificacao2");
        q.setParameter("professor", professor);
        q.setParameter("certificacao", certificacao);
        q.setParameter("mother", isMother);
        TreeSet<Versao> toReturn = new TreeSet<Versao>();
        List<ProfessorVersao> pvs = q.getResultList();
        for (ProfessorVersao pv : pvs) {
            toReturn.add(pv.getVersao());
        }
        return toReturn;
    }

    /**
     * Retorna todas as versões que o usuario(professor) tem acesso
     * limitado a certificação passada, versões que não sejam da Certificação
     * passada são ignoradas. 
     * Possibilita filtro para versão superior
     * @param professor
     * @param certificacao
     * @param isMother
     * @return Lista de Versões superior ou normal.
     */
    @Override
    public Set<Versao> buscarVersoesComMinimoQuestoes(int minQuestoes, Certificacao certificacao, boolean versaoMother) {
        Set<Versao> toReturn = buscarVersoesComMinimoQuestoes(minQuestoes, certificacao);
        Set<Versao> toRemove = new HashSet<Versao>();
        for (Versao v : toReturn) {
            if (versaoMother && !v.isMother()) {
                toRemove.add(v);
            } else if (!versaoMother && v.isMother()) {
                toRemove.add(v);
            }
        }
        toReturn.removeAll(toRemove);
        return toReturn;
    }

    /**
     * Retorna todas as versões que possuem no mínimo
     * a quantidade de questões cadastradas passada como 
     * parâmetro e que possuem a certificação informada.
     * @param minQuestoes cadastradas para a versão
     * @param certificacao filtro para versão
     * @return Set de versões dentro do perfil.
     */
    @Override
    public Set<Versao> buscarVersoesComMinimoQuestoes(int minQuestoes, Certificacao certificacao) {
        Set<Versao> toReturn = buscarVersoesComMinimoQuestoes(minQuestoes);
        Set<Versao> toRemove = new TreeSet<Versao>();
        for (Versao v : toReturn) {
            if (!v.getCertificacao().equals(certificacao)) {
                toRemove.add(v);
            }
        }
        toReturn.removeAll(toRemove);
        return toReturn;
    }

    /**
     * Retorna todas as versões que possuem no mínimo
     * a quantidade de questões cadastradas passada como 
     * parâmetro.
     * @param minQuestoes cadastradas para a versão
     * @return Set de versões
     */
    @Override
    public Set<Versao> buscarVersoesComMinimoQuestoes(int minQuestoes) {
        Set<Versao> toReturn = new TreeSet<Versao>();
        for (Long id : versoesIdMinQuestoes(minQuestoes)) {
            Versao v = manager.find(Versao.class, id);
            if (v.getVersaoMother() != null && !toReturn.contains(v.getVersaoMother())) {
                toReturn.add(v.getVersaoMother());
            }
            toReturn.add(v);
        }
        return toReturn;
    }

    /**
     * Retorna o id das versões que possuem a quantidade
     * mínima de questões necessárias.
     * @param minQuestoes
     * @return Set com ids das versões dentro do perfil.
     */
    private Set<Long> versoesIdMinQuestoes(int minQuestoes) {
        Query q = manager.createNamedQuery("VersaoBean.versoesIdMinQuestoes");
        q.setParameter("qtdade", minQuestoes);
        q.setParameter("statusQuestao", true);
        Set<Long> toReturn = new HashSet<Long>(q.getResultList());
        return toReturn;
    }

    /**
     * Conta a quantidade de questoes de uma versão baseado
     * no idioma e na versão passada.
     * Se linguagem nula conta tudo.
     * @param versao
     * @param linguagem
     * @return 
     */
    @Override
    public Long contarQuestoesDaVersao(Versao versao, Linguagem linguagem) {
        Long toReturn = null;
        Query q = null;
        if (linguagem == null) {
            if (!versao.isMother()) {
                q = manager.createNamedQuery("VersaoBean.contarQuestoesDaVersaoLiguagemNula");
            } else {
                q = manager.createNamedQuery("VersaoBean.contarQuestoesDaVersaoLiguagemNulaMother");
            }
        } else {
            if (!versao.isMother()) {
                q = manager.createNamedQuery("VersaoBean.contarQuestoesDaVersaoLiguagemInformada");
            } else {
                q = manager.createNamedQuery("VersaoBean.contarQuestoesDaVersaoLiguagemInformadaMother");
            }
            q.setParameter("linguagem", linguagem);
        }
        q.setParameter("versao", versao);
        q.setParameter("statusQuestao", true);
        toReturn = (Long) q.getSingleResult();
        return toReturn;
    }

    @Override
    public List<Versao> buscarTodasVersoesPorTipo(boolean isMother, Certificacao certificacao) {
        Query q = manager.createNamedQuery("VersaoBean.buscarTodasVersoesPorTipo");
        q.setParameter("mother", isMother);
        q.setParameter("certificacao", certificacao);
        return q.getResultList();
    }

    @Override
    public List<Versao> buscarTodasVersoesPorTipo(boolean isMother) {
        Query q = manager.createNamedQuery("VersaoBean.buscarTodasVersoesPorTipo2");
        q.setParameter("mother", isMother);
        return q.getResultList();
    }

    @Override
    public Integer quantidadeDeVersoesSimples(Versao versaoMother) {
        if (!versaoMother.isMother()) {
            return 0;
        }
        Query q = manager.createNamedQuery("VersaoBean.quantidadeDeVersoesSimples");
        q.setParameter("versaoMother", versaoMother);
        Long l = (Long) q.getSingleResult();
        return l.intValue();
    }

    @Override
    public Set<Versao> buscarVersoesFilhasDaMother(Versao mother) {
        if (!mother.isMother()) {
            return null;
        }
        Query q = manager.createNamedQuery("VersaoBean.buscarVersoesFilhasDaMother");
        q.setParameter("versaoMother", mother);
        try {
            return new TreeSet<Versao>(q.getResultList());
        } catch (NoResultException e) {
            return null;
        }
    }
}
